package com.neiru.divider.activity;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;

import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.Gallery;
import android.widget.Toast;
import android.widget.Gallery.LayoutParams;

import com.neiru.divider.R;
import com.neiru.divider.bean.Ball;
import com.neiru.divider.bean.Direction;
import com.neiru.divider.bean.Divider;
import com.neiru.divider.bean.Level;
import com.neiru.divider.bean.Position;
import com.neiru.divider.bean.Section;
import com.neiru.divider.constants.ActivityConstants;
import com.neiru.divider.constants.Axis;
import com.neiru.divider.constants.BallColor;
import com.neiru.divider.constants.DialogConstants;
import com.neiru.divider.constants.ThreadConstants;
import com.neiru.divider.thread.SectionThread;
import com.neiru.divider.view.PlayView;

public class Play extends Activity implements OnTouchListener {
	private PlayView playView;

	private Integer touchedSectionIndex = null;
	
	private List<Section> sections;
	private List<SectionThread> sectionThreads;
	private Divider divider;
	
	private Position touchStartPosition;
	private Position touchEndPosition;

	private Level level = null;
	private Long startTimeInMillis;
	private Long endTimeInMillis;
	private Long score = null;
	private Integer dividerCounter;
	private Handler myHandler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case ThreadConstants.INVALIDATE_MESSAGE:
				Play.this.playView.invalidate();
				break;
			case ThreadConstants.REMOVE_FINISHED_MESSAGE:
				divideSection();
				playView.setDivider(null);
				Play.this.divider = null;
				if(checkComplete()) {
						(new Thread() {
							public void run() {
								try {
									Thread.sleep(1000);
								} catch (InterruptedException e) {
								} finally {
									levelComplete();
								}
							}
						}).start();
				}
				break;
			case ThreadConstants.GAME_OVER:
				Play.this.killAllThreads();
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
				} finally {
					Play.this.finish();
				}
				break;
			}
		}
	};
	
	class RefreshRunner implements Runnable {

		@Override
		public void run() {
			while(Play.this.score == null) {
				Message msg = new Message();
				msg.what = ThreadConstants.INVALIDATE_MESSAGE;
				Play.this.myHandler.sendMessage(msg);
				
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
				}
			}
		}
		
	}
	
	private Thread playThread = new Thread(new RefreshRunner());

	private void divideSection() {
		SectionThread sectionThread = sectionThreads.get(touchedSectionIndex);

		SectionThread newSectionThread = sectionThread.divide();

		sectionThreads.add(newSectionThread);
		sections.add(newSectionThread.getSection());

		playView.addSection(newSectionThread.getSection());
		playView.addLine(sectionThread.getDivider().getStartPosition(), sectionThread.getDivider().getFinalPosition(), sectionThread.getDivider().getAxis());
		sectionThread.setDivider(null);
	}
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        
        this.startTimeInMillis = Calendar.getInstance().getTimeInMillis();
        this.dividerCounter = 0;
        
        if(savedInstanceState != null) {
        	this.level = (Level)savedInstanceState.getSerializable(ActivityConstants.PLAY_LEVEL_DATA_NAME);
        }
        if(this.level == null && getIntent().getExtras() != null) {
        	this.level = (Level)getIntent().getExtras().getSerializable(ActivityConstants.PLAY_LEVEL_DATA_NAME);
        }
        if(this.level == null) {
        	this.level = new Level(1, new ArrayList<Integer>(), 3, 1, 3, true);
        }
        
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
                                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        
        this.playView = new PlayView(this);
        this.sectionThreads = new ArrayList<SectionThread>();
        this.sections = new ArrayList<Section>();
        playView.setLayoutParams(new Gallery.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
        initialize();
        Integer bottom = getWindowManager().getDefaultDisplay().getHeight();
        Integer right = getWindowManager().getDefaultDisplay().getWidth();
        playView.inicialize(right, bottom);
        setContentView(playView);
        playView.setOnTouchListener(this);
        playThread.start();
    }
    private void initialize() {
    	Integer bottom = getWindowManager().getDefaultDisplay().getHeight();
    	Integer right = getWindowManager().getDefaultDisplay().getWidth();
    	Section section = new Section();
    	section.setLeft(0);
    	section.setRight(right);
    	section.setTop(0);
    	section.setBottom(bottom);
    	
    	Random random = new Random(Calendar.getInstance().getTimeInMillis());
    	for(int i=0; i < this.level.getBalls(); i++) {
    		Double r1 = random.nextDouble();
    		Double r2 = random.nextDouble();
    		Double r3 = random.nextDouble();
    		Double r4 = random.nextDouble();
    		Double r5 = random.nextDouble();
    		Double r6 = random.nextDouble();
    		Double r7 = random.nextDouble();
    		Double r8 = random.nextDouble();
    		
    		Double initialX = section.getRight()*r7;
    		Double initialY = section.getBottom()*r8;
    		
    		Double directionX = r1>0.5?r2*10:((-10)*r3);
    		Double directionY = r4>0.5?r5*10:((-10)*r6);
    		Direction ball0InitialDirection = new Direction(directionX,directionY);
    		Position ball0InitialPosition = new Position(initialX,initialY);
    		Ball ball = new Ball(ball0InitialDirection,ball0InitialDirection,ball0InitialPosition, this.level.getBallsRadio(),BallColor.BLUE);
    		ball.setSpeed(this.level.getSpeed());
    		section.addBall(ball);
    	}
    	this.playView.addSection(section);
    	this.sections.add(section);
    	SectionThread sectionThread = new SectionThread(myHandler, section);
    	sectionThreads.add(sectionThread);
    	sectionThread.start();
    }
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		Float xF = new Float(event.getX());
		Float yF = new Float(event.getY());
		Double x = xF.doubleValue();
		Double y = yF.doubleValue();
		
		switch(event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				this.touchStartPosition = new Position(x, y);
				break;
			case MotionEvent.ACTION_UP:
				this.touchEndPosition = new Position(x, y);
				startDividerIfNecessary();
				break;
		}
		return true;
	}
	private void startDividerIfNecessary() {
		if(this.touchStartPosition != null && this.touchEndPosition != null) {
			Double xDifference = difference(this.touchStartPosition.getX(), this.touchEndPosition.getX());
			Double yDifference = difference(this.touchStartPosition.getY(), this.touchEndPosition.getY());
			if( xDifference > yDifference && xDifference > 10) {
				if(startDivider(Axis.AXIS_X))
					this.dividerCounter++;
			} else if(yDifference > 10) {
				if(startDivider(Axis.AXIS_Y))
					this.dividerCounter++;
			}
		}
	}
	
	private boolean startDivider(Axis axis) {
		if(divider == null) {
			int i = 0;
			Section touchedSection = null;
			for(Section section: sections) {
//				if(section.isPositionInSection(touchStartPosition)) {
				if(section.isPositionInSection(touchEndPosition)) {
					this.touchedSectionIndex = i;
					touchedSection = section;
					break;
				}
				i++;
			}
			if(i >= sections.size()) {
				return false;
			}
			Position startPosition = null;
			Double startX = null;
			Double startY = null;
			if(this.touchStartPosition.getX() > touchedSection.getRight()) {
				startX = touchedSection.getRight().doubleValue();
			} else if(this.touchStartPosition.getX() < touchedSection.getLeft()) {
				startX = touchedSection.getLeft().doubleValue();
			} else {
				startX = this.touchStartPosition.getX();
			}
			if(this.touchStartPosition.getY() > touchedSection.getBottom()) {
				startY = touchedSection.getBottom().doubleValue();
			} else if(this.touchStartPosition.getY() < touchedSection.getTop()) {
				startY = touchedSection.getTop().doubleValue();
			} else {
				startY = this.touchStartPosition.getY();
			}
			startPosition = new Position(startX, startY);
			divider = new Divider();
			divider.setAxis(axis);
//			divider.setStartPosition(touchStartPosition);
			divider.setStartPosition(startPosition);
//			Position endPosition = new Position(touchStartPosition.getX().doubleValue(), touchStartPosition.getY().doubleValue());
			Position endPosition = new Position(startPosition.getX().doubleValue(), startPosition.getY().doubleValue());
			divider.setFinalPosition(endPosition);
			divider.setSpeed(1);
			this.sectionThreads.get(i).setDivider(divider);
			this.sectionThreads.get(i).startDivider();
			this.playView.setDivider(divider);
			return true;
		}
		return false;
	}
	
	private Double difference(Double point1, Double point2) {
		return Math.abs(point1 - point2);
	}
	@Override
	protected void onStop() {
		killAllThreads();
		super.onStop();
	}

	@Override
	protected void onPause () {
		killAllThreads();
		super.onPause();
	}
	
	private void killAllThreads() {
		for(SectionThread sectionThread: sectionThreads){
			sectionThread.killAllThreads();
		}
	}
	private boolean checkComplete() {
		boolean complete = true;
		for(Section section: this.sections) {
			if(section.getBalls().size() > 1) {
				complete = false;
			}
		}
		return complete;
	}
	private void levelComplete() {
		killAllThreads();
		this.endTimeInMillis = Calendar.getInstance().getTimeInMillis();
		for(SectionThread sectionThread: this.sectionThreads) {
			sectionThread.killAllThreads();
		}
		calculateScore();
		Intent i = new Intent(Play.this, LevelComplete.class);
		i.putExtra(ActivityConstants.PLAY_LEVEL_DATA_NAME, this.level);
		i.putExtra(ActivityConstants.PLAY_LEVEL_DATA_SCORE, this.score);
		startActivityForResult(i, ActivityConstants.ACTIVITY_LEVELCOMPLETE);
	}
	private void calculateScore() {
		Long time = (this.endTimeInMillis - this.startTimeInMillis);
		Long timePoints = null;
		if((60000 - time) > 0) {
			timePoints =  (60000 - time)/1000;
		} else {
			timePoints = new Long(0);
		}
		Long levelPoints= new Long(1);
		
		Long dividerPoints = null;
		if(this.dividerCounter < (this.level.getBalls()*2)) {
			dividerPoints = new Long((this.level.getBalls()*2) - this.dividerCounter);
		} else {
			dividerPoints = new Long(0);
		}
		
		this.score = this.level.getLevel() * (dividerPoints + levelPoints + timePoints); 
	}
	
	protected void onActivityResult (int requestCode, int resultCode, Intent data) {
		switch(requestCode) {
			case ActivityConstants.ACTIVITY_LEVELCOMPLETE:
				Intent dataIntent = new Intent();
				switch(resultCode) {
				case ActivityConstants.PLAY_RESULT_NEXT_LEVEL:
					dataIntent.putExtra(ActivityConstants.PLAY_LEVEL_DATA_NAME, Play.this.level);
					dataIntent.putExtra(ActivityConstants.PLAY_LEVEL_DATA_SCORE, Play.this.score);
					Play.this.setResult(ActivityConstants.PLAY_RESULT_NEXT_LEVEL,dataIntent);
					Play.this.finish();
					break;
				case ActivityConstants.PLAY_RESULT_FINISH:
				default:
					dataIntent.putExtra(ActivityConstants.PLAY_LEVEL_DATA_NAME, Play.this.level);
					dataIntent.putExtra(ActivityConstants.PLAY_LEVEL_DATA_SCORE, Play.this.score);
					Play.this.setResult(ActivityConstants.PLAY_RESULT_FINISH,dataIntent);
					Play.this.finish();
				}
				break;
		}
	}

}